package top.whysu.gps.service.system.impl;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import top.whysu.gps.cache.CacheManager;
import top.whysu.gps.constant.CodeConstant;
import top.whysu.gps.dao.system.SystemConfigDao;
import top.whysu.gps.dto.system.SystemConfigDTO;
import top.whysu.gps.exception.BusinessException;
import top.whysu.gps.global.ThreadPoolBuilder;
import top.whysu.gps.po.system.SystemConfigPO;
import top.whysu.gps.service.system.SystemConfigService;
import top.whysu.gps.utils.ConverterUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 系统配置类信息业务实现类
 */
@Service
public class SystemConfigServiceImpl implements SystemConfigService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SystemConfigServiceImpl.class);

    @Resource
    private SystemConfigDao systemConfigDao;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private ThreadPoolBuilder threadPoolBuilder;
    /**
     * 弱同步版本号申请可重入锁
     */
    private static ReentrantLock lock = new ReentrantLock(true);


    /**
     * 系统配置缓存锁
     * 使用读写锁：读读共存，读写不共存，写写不共存
     * 设置为公平锁
     */
    private static final ReentrantReadWriteLock systemConfigReadWriteLock = new ReentrantReadWriteLock(true);

    @Override
    public void initializeSystemconfigCache() throws BusinessException {
        systemConfigReadWriteLock.writeLock().lock();
        try {
            List<SystemConfigPO> systemConfigPOList = systemConfigDao.selectSystemConfigAll();
            for (SystemConfigPO systemConfigPO : systemConfigPOList) {
                CacheManager.getSystemconfigCache().put(systemConfigPO.getParamKey(), systemConfigPO.getParamValue());
            }
        } finally {
            systemConfigReadWriteLock.writeLock().unlock();
        }
    }

    /**
     * 使用读写锁：读读共存，读写不共存，写写不共存
     * 设置为公平锁
     */
    private static final ReentrantReadWriteLock threadPoolConfigReadWriteLock = new ReentrantReadWriteLock(true);

    @Override
    public void initializeThreadPoolConfigCache() throws BusinessException {
        threadPoolConfigReadWriteLock.writeLock().lock();
        try {
            List<SystemConfigPO> systemConfigPOList = systemConfigDao.selectThreadPoolConfigAll();
            for (SystemConfigPO systemConfigPO : systemConfigPOList) {
                CacheManager.getThreadpoolconfigCache().put(systemConfigPO.getParamKey(), systemConfigPO.getParamValue());
            }
        } finally {
            threadPoolConfigReadWriteLock.writeLock().unlock();
        }
    }

    @Override
    public String getThreadPoolConfig(String key) {
        threadPoolConfigReadWriteLock.readLock().lock();
        try {
            return CacheManager.getThreadpoolconfigCache().get(key);
        } finally {
            threadPoolConfigReadWriteLock.readLock().unlock();
        }
    }

    @Override
    public void newTxUpdateConfig(String key, String value) throws BusinessException {
        if (StringUtils.isBlank(key)) {
            throw new BusinessException(CodeConstant.Http.EXECUTE_FAIL, "更新配置信息失败，key为空");
        }
        systemConfigReadWriteLock.writeLock().lock();
        try {
            // 更新到缓存
            CacheManager.getSystemconfigCache().put(key, value);
            SystemConfigPO systemConfigPO = new SystemConfigPO();
            systemConfigPO.setParamKey(key);
            systemConfigPO.setParamValue(value);
            // 将配置信息保存到数据库
            systemConfigDao.update(systemConfigPO);
        } finally {
            systemConfigReadWriteLock.writeLock().unlock();
        }
    }

    @Override
    public void updateConfigView(SystemConfigDTO systemConfigDTO) throws BusinessException {
        if (systemConfigDTO != null) {
            newTxUpdateConfig(systemConfigDTO.getParamKey(), systemConfigDTO.getParamValue());
        }
    }

    @Override
    public String getConfig(String key) throws BusinessException {
        systemConfigReadWriteLock.readLock().lock();
        try {
            return CacheManager.getSystemconfigCache().get(key);
        } finally {
            systemConfigReadWriteLock.readLock().unlock();
        }
    }

    /**
     * 批量获取配置信息
     *
     * @param keyList keyList存放的是system_config表中的key值
     * @return
     */
    @Override
    public List<SystemConfigDTO> getConfig(List<String> keyList) {
        List<SystemConfigDTO> result = new ArrayList<>();
        for (String key : keyList) {
            SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
            String val = getConfig(key);
            systemConfigDTO.setParamKey(key);
            systemConfigDTO.setParamValue(val);
            result.add(systemConfigDTO);
        }
        return result;
    }


    @Override
    public void updateConfigList(List<SystemConfigDTO> systemConfigDtos) {
        systemConfigDtos.forEach(item -> {
            newTxUpdateConfig(item.getParamKey(), item.getParamValue());
        });
    }

    @Override
    public int updateThirdConfig(SystemConfigDTO systemConfigDTO) throws BusinessException {
        int result = 1;
        SystemConfigPO systemConfigPO = new SystemConfigPO();
        BeanUtils.copyProperties(systemConfigDTO, systemConfigPO);
        newTxUpdateConfig(systemConfigPO.getParamKey(), systemConfigPO.getParamValue());
        return result;
    }

    @Override
    public List<SystemConfigDTO> selectConfigsByParamId(String paramId) {
        Map<String, Object> params = new HashMap<>();
        params.put("paramId", paramId);
        List<SystemConfigPO> systemConfigPOList = systemConfigDao.selectList(params);
        return ConverterUtils.dto2po(systemConfigPOList, SystemConfigDTO.class);
    }

    @Override
    public List<SystemConfigDTO> selectAllConfigList() {
        List<SystemConfigPO> systemConfigPOList = systemConfigDao.selectList(null);
        return ConverterUtils.dto2po(systemConfigPOList, SystemConfigDTO.class);
    }

}
